#!/bin/bash

declare -g ld_name='ld-linux-aarch64.so.1'
declare -g -A soname_dep_map
declare -g all_deps_list

function relink_elf_deps() {
    local elf=$1
    local replica_path=$2

    for dep in $(patchelf --print-needed $elf | grep -Ev "$ld_name"); do
	local dep_absolute_path=${soname_dep_map[$dep]}
	if [ -n "$dep_absolute_path" ]; then
	    local real_soname=$(basename $dep_absolute_path)
	    [ -e $replica_path/lib/$real_soname ] || cp $dep_absolute_path $replica_path/lib
            patchelf --replace-needed $dep $replica_path/lib/$real_soname $elf
	fi
    done
}

function create_elf_and_libs_replicas() {
    local app_elf=$1
    local filter='not found|not a dynamic executable'

    # ldd can get all the shared object dependencies(direct & indirect) of app elf.
    for dep in $(ldd $app_elf | grep -Ev "$filter" | awk '/=>/ {print $3}'); do
        if [ -f $dep ]; then
	    local dep_absolute_path=$(readlink -f $dep)
	    local soname=$(patchelf --print-soname $dep)
	    [ -z "$soname" ] && soname=$(basename $dep)
	    soname_dep_map[$soname]=$dep_absolute_path
	    all_deps_list+=("$dep_absolute_path")
	fi
    done

    local numa_node_num=$(numactl -H | grep "available:" | awk '{print $2}')
    for i in $(seq 0 $((numa_node_num-1))); do
	local numa_replica_path="/opt/numa-replica/$(basename $app_elf)/numa_$i"
	echo -n "Creating replicas of $(basename $app_elf) and its so libs for numa node $i ..."
	mkdir -p $numa_replica_path "$numa_replica_path/lib"
	cp $app_elf $numa_replica_path
	relink_elf_deps $numa_replica_path/$(basename $app_elf) $numa_replica_path
	# as all_deps_list contains all the deps, no need to call relink_elf_deps recursively,
	# patchelf --replace-needed direct_deps for all deps in the list is equivalent.
	for dep in "${all_deps_list[@]}"; do
	    [ -e "$numa_replica_path/lib/$(basename $dep)" ] || cp $dep "$numa_replica_path/lib"
	    relink_elf_deps "$numa_replica_path/lib/$(basename $dep)" $numa_replica_path
	done
	echo "done"
    done
}

if [ -n "$2" ]; then
    source "$2"
else
    echo "Notice: Make sure that the environment variables are set correctly!"
    echo "You can specify the environment setting scripts in /etc/sysconfig/app-numa-replicas-config,"
    echo "then the environment variables, like LD_LIBRARY_PATH, will be set along with service start"
fi

if [ -n "$1" ]; then
    create_elf_and_libs_replicas "$1"
else
    echo "Error: Path of application elf binary is not specified!"
    echo "Please check service config APP_ELF_PATH in /etc/sysconfig/app-numa-replicas-config"
    exit 1
fi
